package com.yonyou.ucf.mdf.app.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yonyou.cloud.yts.model.TransactionContext;
import com.yonyou.diwork.viewmodel.JsonResponseBuilder;
import com.yonyou.iuap.billcode.common.utils.SpringContextUtil;
import com.yonyou.iuap.ml.MultiLangContext;
import com.yonyou.ucf.mdd.common.model.rule.RuleContext;
import com.yonyou.ucf.mdd.common.model.uimeta.filter.vo.FilterVO;
import com.yonyou.ucf.mdd.common.model.uimeta.filter.vo.QueryPagerVo;
import com.yonyou.ucf.mdd.ext.model.BillContext;
import net.sf.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;


/**
 * Created by Administrator on 2017/12/14.
 */
@RestController
@RequestMapping("/rpc-adapter")
public class RPCAdapterController {

	private Logger logger = LoggerFactory.getLogger(getClass());


	public ObjectMapper objectMapper = new ObjectMapper();

	{
		restMapper();

	}

	private void restMapper() {
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		objectMapper.setVisibility(PropertyAccessor.SETTER, Visibility.NONE);
		objectMapper.setVisibility(PropertyAccessor.GETTER, Visibility.NONE);
		objectMapper.setVisibility(PropertyAccessor.IS_GETTER, Visibility.NONE);
		objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
		objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
	}

	class ParameterTypeReference extends TypeReference<String> {
		private Parameter parameter;

		public ParameterTypeReference(Parameter parameter) {
			this.parameter = parameter;
		}

		@Override
		public Type getType() {
			return parameter.getParameterizedType();
		}
	}

	;

	/**
	 * @param serviceName 全限定名
	 * @param methodName  方法名
	 * @param args        参数
	 */
	@RequestMapping(value = "/gateway", method = RequestMethod.POST)
	public Object commonRpcAdapter(HttpServletRequest request, String serviceName, String methodName, String args) {

		logger.info("interfaceCount,/gateway,serviceName={},methodName={},args={}", serviceName, methodName, args);

		Object ts = request.getAttribute("currentTimeMillis");
		if (ts == null || !(ts instanceof Long)) {
			ts = System.currentTimeMillis();
		}

		Class<?> clazz;
		try {
			clazz = Class.forName(serviceName);
		} catch (ClassNotFoundException e) {
			logger.error(com.yonyou.iuap.ucf.common.i18n.MessageUtils.getMessage("P_YS_PF_GZTORG_0000045718") /* "不正确的服务类名:serviceName=" */ + serviceName + ";methodName=" + methodName + ";args=" + args, e);
			return JsonResponseBuilder.buildFailResponse(MultiLangContext.getInstance().getMessage("com.yonyou.diwork.rpcadapter.controller.RPCAdapterController_0000", new Object[]{}));
		}


		JSONArray argsArray;
		try {
			argsArray = objectMapper.readValue(args, JSONArray.class);
		} catch (Exception e) {
			logger.error(com.yonyou.iuap.ucf.common.i18n.MessageUtils.getMessage("P_YS_PF_GZTORG_0000045674") /* "参数格式不对:serviceName=" */ + serviceName + ";methodName=" + methodName + ";args=" + args, e);
			return JsonResponseBuilder.buildFailResponse(MultiLangContext.getInstance().getMessage("com.yonyou.diwork.rpcadapter.controller.RPCAdapterController_0001", new Object[]{}));
		}
		loop:
		for (Method method : clazz.getMethods()) {
			if (methodName.equals(method.getName())) {
				Parameter[] parameters = method.getParameters();
				Object[] argObjs = new Object[parameters.length];

				if (parameters.length != argsArray.size()) {
					continue;
				}
				if (argsArray != null && argsArray.size() > 0) {
					for (int i = 0; i < argsArray.size(); ++i) {
						String str = argsArray.get(i).toString();
						if (parameters[i].getType().isAssignableFrom(String.class)) {
							ParameterTypeReference typeRef = new ParameterTypeReference(parameters[i]);
							try {
								restMapper();
								argObjs[i] = objectMapper.readValue(str, typeRef);
							} catch (Exception e) {
								argObjs[i] = str;
							}
						} else {
							ParameterTypeReference typeRef = new ParameterTypeReference(parameters[i]);
							try {
									/*解决extPropsString 本应该是字符串类型，转换成json以后的单独处理，
									否则会报Cannot deserialize instance of `java.lang.String` out of START_OBJECT token

									*/
								if (serviceName.equals("com.yonyou.ucf.mdd.ext.service.MddExtRuleApiService")) {
									if (i == 1 && method.getName().equals("executeRule")) {
										restMapper();
										argObjs[i] = JSON.parseObject(str, Class.forName(typeRef.getType().getTypeName()));
									} else if (i == 2 && method.getName().equals("doAction")) {
										RuleContext ruleContext = (RuleContext) JSON.parseObject(str, RuleContext.class);
										JSONObject context = (JSONObject) ruleContext.getBillContext().getTransactionContext();
										//解决ruleContext.getBillContext().getTransactionContext() JSONObject不能转出成TransactionContext，特殊化处理
										TransactionContext transactionContext = JSON.parseObject(context.toJSONString(), TransactionContext.class);
										ruleContext.getBillContext().setTransactionContext(transactionContext);
										argObjs[i] = ruleContext;
									} else {
										restMapper();
										argObjs[i] = objectMapper.readValue(str, typeRef);
									}
								} else if ("com.yonyou.ucf.mdd.ext.ref.service.impl.RefService".equals(serviceName)) {
									if (i == 0 && "getRefData".equals(method.getName())) {
										BillContext billContext = JSON.parseObject(str, BillContext.class);
										argObjs[i] = billContext;
									} else {
										restMapper();
										argObjs[i] = objectMapper.readValue(str, typeRef);
									}
								} else {
									restMapper();
									argObjs[i] = objectMapper.readValue(str, typeRef);
								}
							} catch (Exception e) {
								logger.error(com.yonyou.iuap.ucf.common.i18n.MessageUtils.getMessage("P_YS_PF_GZTORG_0000045711") /* "参数转换失败:serviceName=" */ + serviceName + ";methodName=" + methodName
										+ ";args=" + args, e);
								continue loop;
							}
						}

					}
				}


				Object service = SpringContextUtil.getBean(clazz);
				if (clazz.getName().equals("com.yonyou.ucf.mdd.ext.ref.service.impl.RefService")) {
//                    LinkedHashMap filtervo = (LinkedHashMap) ((LinkedHashMap) argObjs[2]).get("condition");
//                    FilterVO filterVO = JSON.parseObject(JSON.toJSONString(filtervo), FilterVO.class);
//                    ((LinkedHashMap) argObjs[2]).put("condition", filterVO);
					processRefData(argObjs);
				}

				try {
					Object result = method.invoke(service, argObjs);
					logger.info("respense ,path={},ts={},ykj_req={},total cost={}", ((HttpServletRequest) request).getRequestURI(), System.currentTimeMillis(), request.getParameter("ykj_req"), (System.currentTimeMillis() - (Long) ts));
					return JsonResponseBuilder.buildSuccessResponse(result);
				} catch (InvocationTargetException e) {
					logger.error(com.yonyou.iuap.ucf.common.i18n.MessageUtils.getMessage("P_YS_PF_GZTORG_0000045782") /* "服务调用失败:serviceName=" */ + serviceName + ";methodName=" + methodName + ";args=" + args,
							e);
					return JsonResponseBuilder.buildFailResponse(e.getTargetException().getMessage());
				} catch (Exception e) {
					logger.error(com.yonyou.iuap.ucf.common.i18n.MessageUtils.getMessage("P_YS_PF_GZTORG_0000045782") /* "服务调用失败:serviceName=" */ + serviceName + ";methodName=" + methodName + ";args=" + args,
							e);
					return JsonResponseBuilder.buildFailResponse(MultiLangContext.getInstance().getMessage("com.yonyou.diwork.rpcadapter.controller.RPCAdapterController_0002", new Object[]{}) + e.getMessage());
				}
			}
		}
		logger.info(com.yonyou.iuap.ucf.common.i18n.MessageUtils.getMessage("P_YS_PF_GZTORG_0000045714") /* "未找到匹配的方法:serviceName=" */ + serviceName + ";methodName=" + methodName + ";args=" + args);
		return JsonResponseBuilder.buildFailResponse(MultiLangContext.getInstance().getMessage("com.yonyou.diwork.rpcadapter.controller.RPCAdapterController_0003", new Object[]{}));
	}

	public void processRefData(Object[] argObjs) {
		LinkedHashMap filtervo = (LinkedHashMap) ((LinkedHashMap) argObjs[2]).get("condition");
		if (filtervo!=null) {
			FilterVO filterVO = JSON.parseObject(JSON.toJSONString(filtervo), FilterVO.class);
			((LinkedHashMap) argObjs[2]).put("condition", filterVO);
		}
		LinkedHashMap queryPageVoJsonObject = (LinkedHashMap) ((LinkedHashMap) argObjs[2]).get("page");
		if (filtervo!=null) {
			QueryPagerVo queryPagerVo = JSON.parseObject(JSON.toJSONString(queryPageVoJsonObject), QueryPagerVo.class);
			((LinkedHashMap) argObjs[2]).put("page", queryPagerVo);
		}

		LinkedHashMap treeCondition = (LinkedHashMap) ((LinkedHashMap) argObjs[2]).get("treeCondition");
		if (filtervo!=null) {
			FilterVO filterVO = JSON.parseObject(JSON.toJSONString(treeCondition), FilterVO.class);
			((LinkedHashMap) argObjs[2]).put("treeCondition", filterVO);
		}
	}

}
